package com.gmail.dengtao.joe.group.transport.impl;

import com.gmail.dengtao.joe.group.channel.Channel;
import com.gmail.dengtao.joe.group.interceptor.InterceptorStack;
import com.gmail.dengtao.joe.group.member.Member;
import com.gmail.dengtao.joe.group.protocol.ProtocolFactory;
import com.gmail.dengtao.joe.group.protocol.impl.ACKProtocol;
import com.gmail.dengtao.joe.group.protocol.impl.ACKProtocolParser;
import com.gmail.dengtao.joe.group.protocol.impl.DATAProtocol;
import com.gmail.dengtao.joe.group.protocol.impl.DATAProtocolParser;
import com.gmail.dengtao.joe.group.protocol.impl.HELLOProtocol;
import com.gmail.dengtao.joe.group.protocol.impl.HELLOProtocolParser;
import com.gmail.dengtao.joe.group.protocol.impl.IDLEProtocol;
import com.gmail.dengtao.joe.group.protocol.impl.IDLEProtocolParser;
import com.gmail.dengtao.joe.group.protocol.impl.ProtocolFactoryImpl;
import com.gmail.dengtao.joe.group.transport.impl.filter.DataFilter;
import com.gmail.dengtao.joe.group.transport.impl.filter.PacketFilter;
import com.gmail.dengtao.joe.group.transport.impl.filter.ProtocolFilter;
import com.gmail.dengtao.joe.group.transport.impl.handler.ChannelReceiverHandler;
import com.gmail.dengtao.joe.transport.SocketAcceptor;

/**
 * TCPChannelReceiver is used to receiving tcp data from remote member. 
 * @author <a href="mailto:joe.dengtao@gmail.com">DengTao</a>
 * @version 1.0
 * @since 1.0
 */
public class TCPChannelReceiver extends AbstractChannelReceiver {

	protected SocketAcceptor acceptor = null;
	protected AbstractReceiverHandler handler = null;

	/**
	 * Create a UDP channel receiver to receive Datagram data.
	 * @param host receiver will listen this address
	 * @param port receiver will listen on this port
	 * @throws Exception 
	 */
	public TCPChannelReceiver(String host, int port, Channel channel) throws Exception {
		this.host = host;
		this.port = port;
		this.channel = channel;
		Member local = new Member(host, port);
		handler = new ChannelReceiverHandler(channel, local);
		acceptor = new SocketAcceptor(host, port);
		
		ProtocolFactory protocolFactory = new ProtocolFactoryImpl();
		protocolFactory.register(String.valueOf(HELLOProtocol.SYMBOL), new HELLOProtocolParser());
		protocolFactory.register(String.valueOf(IDLEProtocol.SYMBOL), new IDLEProtocolParser());
		protocolFactory.register(String.valueOf(DATAProtocol.SYMBOL), new DATAProtocolParser());
		protocolFactory.register(String.valueOf(ACKProtocol.SYMBOL), new ACKProtocolParser());
		
		acceptor.getFilterChain().addLast("DataFilter", new DataFilter());
		acceptor.getFilterChain().addLast("PacketFilter", new PacketFilter());
		acceptor.getFilterChain().addLast("ProtocolFilter", new ProtocolFilter(protocolFactory));
		acceptor.init();
	}
	
	@Override
	public synchronized void start(Object receiverLock) throws Exception {
		if (start) {
			throw new IllegalStateException("This receiver has already been started!");
		} else {
			start = true;
		}
		
		// config handler
		handler.setIdleTimeForRead(idleTimeForRead);
		handler.setInterceptorStack(interceptorStack);
		
		acceptor.setHandler(handler);
		acceptor.start(receiverLock);
	}

	@Override
	public synchronized void stop() throws Exception {
		acceptor.stop();
	}

	@Override
	public void setSelectTimeout(int selectTimeout) {
		super.setSelectTimeout(selectTimeout);
		acceptor.setSelectTimeout(selectTimeout);
	}

	@Override
	public void setReceiveBufferSize(int receiveBufferSize)
			throws IllegalArgumentException {
		super.setReceiveBufferSize(receiveBufferSize);
		acceptor.setReceiveBufferSize(receiveBufferSize);
	}

	@Override
	public void setIdleTimeForRead(int idleTimeForRead) {
		super.setIdleTimeForRead(idleTimeForRead);
		handler.setIdleTimeForRead(idleTimeForRead);
	}

	@Override
	public void setInterceptorStack(InterceptorStack interceptorStack) {
		super.setInterceptorStack(interceptorStack);
		handler.setInterceptorStack(interceptorStack);
	}

}
